package com.jic.member.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jic.common.redis.RedisClientTemplate;
import com.jic.member.service.JsApiService;
import com.jic.member.service.RedisServiceEx;
import com.jic.member.utils.SignatureUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.net.ssl.*;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName JsApiServiceImpl
 * @Description JsApi
 * @Author zzy
 * @Date 2020/6/17 上午10:52
 */
@Component
@Slf4j
public class JsApiServiceImpl implements JsApiService {


    @Value("${wechant2.login.accessTokenUrl}")
    private String weixinLoginUrl;

    @Value("${wechant2.login.refreshTokenUrl}")
    private String weixinRefreshLoginUrl;

    @Value("${wechant2.login.getInfoUrl}")
    private String getInfoUrl;

    @Value("${wechant2.appid}")
    private String appid;

    @Value("${wechant2.secret}")
    private String secret;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RedisClientTemplate redisService;

    @Autowired
    private RedisServiceEx redisServiceEx;


    @Override
    public String downloadMedia(String mediaId) throws Exception {
        String accessToken = this.getWeiXinApiToken();
        String url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token="
                + accessToken + "&media_id=" + mediaId;

        //进行下载图片
        //保存头像信息
        //下载头像并且加密base64
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        Response response = client.newCall(request).execute();
        String images = Base64.getEncoder().encodeToString(response.body().bytes());
        return images;
    }

    @Override
    public void init(String appid, String secret) {
        this.appid = appid;
        this.secret = secret;
    }

    @Override
    public String getQrcode(String phone) throws Exception {

        String accessToken = this.getWeiXinApiToken();
        OkHttpClient client = new OkHttpClient();
        String postUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;

        //String param = "{\"action_name\": \"QR_LIMIT_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": "+phone+"}}}";
        RequestBody body = new FormBody.Builder()
                .add("action_name", "QR_LIMIT_STR_SCENE")
                .add("action_info", "{\"scene\": {\"scene_str\": " + phone + "}")
                .build();

        Request request = new Request.Builder()
                .url(postUrl)
                .post(body)
                .build();

        Response response = client.newCall(request).execute();
        if (response.code() == HttpStatus.SC_OK) {
            String str = response.body().string();
            Map<String, String> map = objectMapper.readValue(str, Map.class);
            if (null != map && map.size() > 0) {
                String ticket = (String) map.get("ticket");
                String imageUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
                Request request2 = new Request.Builder()
                        .url(imageUrl)
                        .get()
                        .build();
                Response response2 = client.newCall(request2).execute();
                String images = Base64.getEncoder().encodeToString(response2.body().bytes());
                return images;
            } else {
                throw new RuntimeException("获取ticket失败");
            }

        } else {
            throw new RuntimeException("获取ticket失败");
        }
    }

    @Override
    public String getWeiXinApiToken() throws Exception {

        String access_token = null;
        access_token = redisService.get(redisServiceEx.getWeiXinApiTokenKey());

        if (null == access_token) {
            String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appid, secret);
            OkHttpClient.Builder mBuilder = new OkHttpClient.Builder();
            mBuilder.sslSocketFactory(createSSLSocketFactory());
            mBuilder.hostnameVerifier(new TrustAllHostnameVerifier());
            OkHttpClient client = mBuilder.build();

            Request request = new Request.Builder()
                    .url(url)
                    .get()
                    .build();

            Response response = client.newCall(request).execute();
            String result = response.body().string();
            Map<String, Object> map = objectMapper.readValue(result, Map.class);
            log.info("-----------------------getWeiXinApiToken的日志" + map);

            access_token = (String) map.get("access_token");
            Integer expires_in = (Integer) map.get("expires_in");
            redisService.setex(redisServiceEx.getWeiXinApiTokenKey(), new Integer(expires_in - 200), access_token);
        }
        return access_token;
    }

    @Override
    public Map<String, String> getWeiXinApiSign(String url) throws Exception {
        String ticket = null;
        ticket = redisService.get(redisServiceEx.getWeiXinApiTicketKey());
        if (StringUtils.isBlank(ticket)) {
            String token = getWeiXinApiToken();
            String requestUrl = String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=%s", token, "jsapi");
            OkHttpClient.Builder mBuilder = new OkHttpClient.Builder();
            mBuilder.sslSocketFactory(createSSLSocketFactory());
            mBuilder.hostnameVerifier(new TrustAllHostnameVerifier());
            OkHttpClient client = mBuilder.build();
            Request request = new Request.Builder()
                    .url(requestUrl)
                    .get()
                    .build();

            Response response = client.newCall(request).execute();
            String result = response.body().string();
            Map<String, Object> map = objectMapper.readValue(result, Map.class);
            log.info("-----------------------getWeiXinApiSign的日志:{}" + map);
            ticket = (String) map.get("ticket");
            Integer expires_in = (Integer) map.get("expires_in");
            //缓存ticket;
            redisService.setex("", new Integer(expires_in - 200), ticket);
        }
        Map<String, String> result = SignatureUtil.sign(ticket, url);
        result.put("appId", appid);
        return result;
    }

    public Map<String, Object> getWeixinToken(String code) throws Exception {
        String url = weixinLoginUrl + "?appid=" + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
        //获取weixin access_token 与 refresh_token
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        Response response = client.newCall(request).execute();
        final String result = response.body().string();

        Map<String, Object> map = objectMapper.readValue(result, Map.class);
        log.info("getWeixinToken------------>:{}" + map);
        if (null != map && map.size() > 0) {
            if (map.get("openid") == null) {
                //获取token失败
                throw new RuntimeException("获取token失败");
            }
            String openId = (String) map.get("openid");
            String access_token = (String) map.get("access_token");

            Map<String, Object> userMap = getWeixinUserInfo(access_token, openId);
            String openid = (String) userMap.get("openid");
            redisService.setex(openid, 3600 * 24, objectMapper.writeValueAsString(userMap));
            return userMap;
        } else {
            throw new RuntimeException("获取token失败");
        }
    }
    public Map<String, Object> getMiniProgramToken(String code) throws Exception {
        String url = weixinLoginUrl + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
        //获取weixin access_token 与 refresh_token
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        Response response = client.newCall(request).execute();
        final String result = response.body().string();

        Map<String, Object> map = objectMapper.readValue(result, Map.class);
        log.info("getWeixinToken------------>:{}" + map);
        if (null != map && map.size() > 0) {
            if (map.get("openid") == null) {
                //获取token失败
                throw new RuntimeException("获取token失败");
            }
            String openId = (String) map.get("openid");
            String access_token = (String) map.get("access_token");

//            Map<String, Object> userMap = getWeixinUserInfo(access_token, openId);
//            String openid = (String) userMap.get("openid");
//            redisService.setex(openid, 3600 * 24, objectMapper.writeValueAsString(userMap));

            Map<String,Object> userMap = new HashMap<>();
            userMap.put("openId",openId);
            return userMap;
        } else {
            throw new RuntimeException("获取token失败");
        }
    }

    public Map<String, Object> getWeixinTokenByOpenId(String openid) throws Exception {
        String userMap = redisService.get(openid);
        Map<String, Object> map = objectMapper.readValue(userMap, Map.class);
        return map;
    }

    public Map<String, Object> getWeixinUserInfo(String access_token, String openId) throws Exception {
        //获取微信上的基本信息
        String url = getInfoUrl + "?access_token=" + access_token + "&openid=" + openId + "&lang=zh_CN";
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        Response response = client.newCall(request).execute();
        final String result = response.body().string();
        Map<String, Object> map = objectMapper.readValue(result, Map.class);
        log.info("getWeixinUserInfo=============>:{}",map);
        if (null != map && map.size() > 0) {
            if (map.get("openid") == null) {
                //获取token失败
                throw new RuntimeException("获取token失败");
            }
            return map;
        } else {
            throw new RuntimeException("获取token失败");
        }
    }

    private static class TrustAllCerts implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    private static class TrustAllHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    private static SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());

            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }

        return ssfFactory;
    }
}
